package com.ruoyi.site.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils; // 用于密码加密/匹配
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.site.domain.SiteLoginUser;
import com.ruoyi.site.domain.UserAuths;
import com.ruoyi.site.domain.Users;
import com.ruoyi.site.service.IAuthService;
import com.ruoyi.site.service.IMailService;
import com.ruoyi.site.service.IUserAuthsService;
import com.ruoyi.site.service.IUsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class AuthServiceImpl implements IAuthService
{
    @Autowired
    private IUsersService usersService;

    @Autowired
    private IUserAuthsService userAuthsService; // 注入 UserAuths 的 Service

    @Autowired
    private TokenService tokenService;

    @Autowired
    private IMailService mailService;

    @Autowired
    private RedisCache redisCache;
    private static final String VERIFY_EMAIL_KEY_PREFIX = "site:verify_email:";
    private static final int VERIFY_EMAIL_EXPIRE_HOURS = 24;

    @Value("${google.oauth.client-id}")
    private String clientId;

    @Value("${google.oauth.client-secret}")
    private String clientSecret;

    @Value("${google.oauth.redirect-uri}")
    private String redirectUri; // 后端回调地址

    @Value("${app.frontend-url}")
    private String frontendUrl; // 用于构建前端验证链接

    // Google 授权服务器端点
    private static final String GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
    private static final String GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v3/userinfo";

    // 注入 RestTemplate (需要在 Spring 配置中定义其 Bean)
    private final RestTemplate restTemplate = new RestTemplate();

    /**
     * 注册用户、创建 UserAuths 记录，并发送邮箱验证邮件。
     */
    @Override
    @Transactional // 确保 Users 和 UserAuths 的创建是原子性的
    public void register(String email, String nickname, String password)
    {
        // 1. 检查 email 是否已被注册
        if (usersService.selectUsersByEmail(email) != null)
        {
            throw new RuntimeException("This email address is already registered.");
        }

        // 3. 创建 Users 记录
        Users newUser = new Users();
        newUser.setEmail(email);
        newUser.setNickname(nickname);
        newUser.setCreatedAt(new Date());
        newUser.setUpdatedAt(new Date());
        // 其他默认字段如 subscriptionStatus, currentPlanId 等设置默认值

        // 插入 Users，并确保能获取到新生成的 userId (若若依Mapper配置了 useGeneratedKeys)
        usersService.insertUsers(newUser);

        // 4. 创建 UserAuths 记录
        UserAuths auth = new UserAuths();
        // 确保 Users 插入后，newUser.getUserId() 可以拿到自增 ID
        auth.setUserId(newUser.getUserId());
        auth.setIdentityType("email");
        auth.setIdentifier(email);
        // 对密码进行加密存储
        auth.setCredential(SecurityUtils.encryptPassword(password));
        auth.setIsVerified(0); // 0 = 否，等待验证
        auth.setCreatedAt(new Date());
        auth.setUpdatedAt(new Date());
        userAuthsService.insertUserAuths(auth);

        // 5. 生成验证 Token 并发送邮件

        String verificationToken = UUID.randomUUID().toString();
        String redisKey = VERIFY_EMAIL_KEY_PREFIX + verificationToken;

        redisCache.setCacheObject(redisKey, email, VERIFY_EMAIL_EXPIRE_HOURS, TimeUnit.HOURS);

        String verificationUrl = frontendUrl + "/verify?token=" + verificationToken + "&email=" + email;

        // 调用邮件服务发送验证邮件
        try {
            mailService.sendVerificationEmail(email, verificationUrl);
        } catch (Exception e) {
            // 记录日志并抛出英文错误，传递原异常 e
            throw new RuntimeException("Failed to send verification email to " + email + ".", e);
        }
    }

    /**
     * 邮箱验证并登录。
     * @param email 注册邮箱
     * @param code 邮箱中携带的验证 Token
     */
    @Override
    @Transactional
    public String verifyEmailAndLogin(String email, String code)
    {
        String redisKey = VERIFY_EMAIL_KEY_PREFIX + code;

        // 1. 验证 code/token 的有效性（从 Redis 中校验）
        String storedEmail = redisCache.getCacheObject(redisKey);

        if (storedEmail == null) {
            // 错误信息改为英文
            throw new RuntimeException("Verification link is invalid or expired. Please register again.");
        }

        if (!storedEmail.equalsIgnoreCase(email)) {
            // 错误信息改为英文
            throw new RuntimeException("Verification information mismatch.");
        }

        // 2. 查找 UserAuths 记录
        UserAuths auth = userAuthsService.selectUserAuthsByIdentifier("email", email);
        if (auth == null) {
            redisCache.deleteObject(redisKey);
            // 错误信息改为英文
            throw new RuntimeException("Verification failed: User not found.");
        }

        if (auth.getIsVerified() == 1) {
            // 已验证，直接返回登录 Token（无需再次清理，但为确保幂等性，仍可清理 Redis 记录）
            redisCache.deleteObject(redisKey);

            // 重新获取用户信息并生成 Token，确保返回最新的 Token
            Users siteUser = usersService.selectUsersByUserId(auth.getUserId());
            SiteLoginUser loginUser = new SiteLoginUser(auth.getUserId(), null, siteUser, null);
            return tokenService.createToken(loginUser);
        }

        // 3. 更新 UserAuths 的 isVerified 状态为 1 (是)
        auth.setIsVerified(1);
        auth.setUpdatedAt(new Date());
        userAuthsService.updateUserAuths(auth);

        // 4. 获取 Users 信息
        Users siteUser = usersService.selectUsersByUserId(auth.getUserId());
        if (siteUser == null) {
            redisCache.deleteObject(redisKey);
            // 错误信息改为英文
            throw new RuntimeException("System error: User profile data is missing.");
        }

        // 5. 创建 SiteLoginUser 对象
        SiteLoginUser loginUser = new SiteLoginUser(auth.getUserId(), null, siteUser, null);

        // 6. 清理验证 Token (从 Redis 中删除，确保一次性使用)
        redisCache.deleteObject(redisKey);

        // 7. 生成并返回 JWT Token
        return tokenService.createToken(loginUser);
    }

    /**
     * 用户登录。
     */
    @Override
    public String login(String email, String password)
    {
        // 1. 根据 email 查找 UserAuths 记录
        UserAuths auth = userAuthsService.selectUserAuthsByIdentifier("email", email);

        if (auth == null) {
            // 错误信息改为英文
            throw new RuntimeException("Account not registered with this email address.");
        }

        // 2. 检查密码是否匹配
        if (!SecurityUtils.matchesPassword(password, auth.getCredential())) {
            // 错误信息改为英文
            throw new RuntimeException("Incorrect password.");
        }

        // 3. 检查邮箱是否已验证
        if (auth.getIsVerified() != 1) {
            // 错误信息改为英文
            throw new RuntimeException("Please verify your email address first.");
        }

        // 4. 获取 Users 信息
        Users siteUser = usersService.selectUsersByUserId(auth.getUserId());

        // 5. 创建 SiteLoginUser 对象
        SiteLoginUser loginUser = new SiteLoginUser(auth.getUserId(), null, siteUser, null);

        // 6. 生成并返回 JWT Token
        return tokenService.createToken(loginUser);
    }

    /**
     * 处理 Google OAuth 回调，完成授权码交换、用户登录/注册流程。
     */
    @Override
    @Transactional
    public String handleGoogleLogin(String code) throws Exception
    {
        // 1. 交换授权码 (code) 获取 Access Token
        String accessToken = getAccessTokenFromGoogle(code);

        // 2. 使用 Access Token 获取用户信息 (Google ID, Email, Name)
        GoogleUserInfo userInfo = getUserInfoFromGoogle(accessToken);

        // 确保获取到了关键信息
        if (StringUtils.isBlank(userInfo.getSub()) || StringUtils.isBlank(userInfo.getEmail())) {
            throw new RuntimeException("未能从 Google 获取到足够的用户信息");
        }

        // Google ID 作为 UserAuths 的唯一标识
        String googleIdentifier = userInfo.getSub();
        String email = userInfo.getEmail();

        // 3. 检查用户是否存在 (核心业务逻辑)
        UserAuths auth = userAuthsService.selectUserAuthsByIdentifier("google", googleIdentifier);

        if (auth == null) {
            // =======================================================
            // A. 新用户：执行注册流程 (创建 Users 和 UserAuths)
            // =======================================================

            // 3.1 检查邮箱是否已被其他渠道（例如邮箱/密码）注册
            Users existingUser = usersService.selectUsersByEmail(email);

            Users siteUser;
            if (existingUser != null) {
                // 如果邮箱已存在，则将 Google 渠道关联到现有用户
                siteUser = existingUser;
            } else {
                // 邮箱不存在，创建新的 Users 记录
                siteUser = new Users();
                // 使用 Google 返回的 Name 作为 Nickname
                siteUser.setNickname(userInfo.getName());
                siteUser.setEmail(email);
                siteUser.setCreatedAt(new Date());
                siteUser.setUpdatedAt(new Date());
                // 设置默认头像 (userInfo.getPicture() 是头像 URL)
                siteUser.setAvatar(userInfo.getPicture());
                // ... 设置其他默认字段 ...
                usersService.insertUsers(siteUser);
            }

            // 3.2 创建 UserAuths 记录
            UserAuths newAuth = new UserAuths();
            newAuth.setUserId(siteUser.getUserId());
            newAuth.setIdentityType("google");
            newAuth.setIdentifier(googleIdentifier);
            newAuth.setIsVerified(1); // 默认视为已验证（Google已验证Email）
            newAuth.setLastLoginAt(new Date());
            newAuth.setCreatedAt(new Date());
            newAuth.setUpdatedAt(new Date());
            userAuthsService.insertUserAuths(newAuth);

            auth = newAuth; // 设置为当前认证记录

        } else {
            // =======================================================
            // B. 老用户：执行登录流程 (更新最后登录时间)
            // =======================================================

            // 更新最后登录时间
            auth.setLastLoginAt(new Date());
            userAuthsService.updateUserAuths(auth);

            // 刷新 Users 信息 (例如更新头像)
            // Users siteUser = usersService.selectUsersByUserId(auth.getUserId());
            // if (!StringUtils.equals(siteUser.getAvatar(), userInfo.getPicture())) {
            //    siteUser.setAvatar(userInfo.getPicture());
            //    usersService.updateUsers(siteUser);
            // }
        }

        // 4. 生成并返回 JWT Token
        Users finalUser = usersService.selectUsersByUserId(auth.getUserId());
        SiteLoginUser loginUser = new SiteLoginUser(auth.getUserId(), null, finalUser, Collections.emptySet());

        return tokenService.createToken(loginUser);
    }

    // =======================================================
    // 私有辅助方法
    // =======================================================

    /**
     * 向 Google 交换 Access Token
     */
    private String getAccessTokenFromGoogle(String code)
    {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        // 构造请求体 (Form Data)
        String requestBody = String.format(
                "code=%s&client_id=%s&client_secret=%s&redirect_uri=%s&grant_type=authorization_code",
                code, clientId, clientSecret, redirectUri
        );

        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);

        try {
            ResponseEntity<String> response = restTemplate.exchange(
                    GOOGLE_TOKEN_URL, HttpMethod.POST, entity, String.class
            );

            JSONObject json = JSONObject.parseObject(response.getBody());
            String accessToken = json.getString("access_token");

            if (StringUtils.isBlank(accessToken)) {
                // 错误信息改为英文
                throw new Exception("Google Token exchange failed: " + json.getString("error_description"));
            }
            return accessToken;
        } catch (Exception e) {
            throw new RuntimeException("Network error during Google Token exchange.", e);
        }
    }

    /**
     * 辅助方法：使用 Access Token 获取 Google 用户信息
     */
    private GoogleUserInfo getUserInfoFromGoogle(String accessToken)
    {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + accessToken);

        HttpEntity<String> entity = new HttpEntity<>(headers);

        try {
            ResponseEntity<String> response = restTemplate.exchange(
                    GOOGLE_USERINFO_URL, HttpMethod.GET, entity, String.class
            );

            // 将 JSON 响应直接映射到我们定义的用户信息类
            JSONObject json = JSONObject.parseObject(response.getBody());
            return new GoogleUserInfo(
                    json.getString("sub"),
                    json.getString("email"),
                    json.getString("name"),
                    json.getString("picture")
            );
        } catch (Exception e) {
            throw new RuntimeException("Failed to retrieve Google user info.", e);
        }
    }

    /**
     * 临时内部类：用于封装 Google 返回的用户信息
     */
    private static class GoogleUserInfo {
        private String sub;      // Google 唯一 ID
        private String email;    // 用户邮箱
        private String name;     // 用户昵称
        private String picture;  // 用户头像 URL

        public GoogleUserInfo(String sub, String email, String name, String picture) {
            this.sub = sub;
            this.email = email;
            this.name = name;
            this.picture = picture;
        }

        // Getter 方法 (省略，假设 Lombok 或手动添加)
        public String getSub() { return sub; }
        public String getEmail() { return email; }
        public String getName() { return name; }
        public String getPicture() { return picture; }
    }
}